package com.autonavi.yunda.yunji.controller;

import com.autonavi.yunda.yunji.common.exception.AmapException;
import com.autonavi.yunda.yunji.common.exception.AmapExceptionCode;
import com.autonavi.yunda.yunji.controller.aspect.DecodeExtraData;
import com.autonavi.yunda.yunji.controller.interceptor.NeedOperationLog;
import com.autonavi.yunda.yunji.controller.request.GrayPublishRequest;
import com.autonavi.yunda.yunji.controller.request.InterfaceConfigRequest;
import com.autonavi.yunda.yunji.controller.request.InterfaceConfigUpdateRequest;
import com.autonavi.yunda.yunji.core.config.ApplicationEnvConfig;
import com.autonavi.yunda.yunji.core.enums.OperationRecordType;
import com.autonavi.yunda.yunji.core.model.condition.InterfaceQueryCondition;
import com.autonavi.yunda.yunji.core.model.dto.InterfaceConfigDTO;
import com.autonavi.yunda.yunji.core.model.dto.ProjectDTO;
import com.autonavi.yunda.yunji.core.service.IIpService;
import com.autonavi.yunda.yunji.core.service.InterfaceConfigService;
import com.autonavi.yunda.yunji.core.service.ProjectService;
import com.autonavi.yunda.yunji.core.service.thirdpartyservice.FalconInterfaceService;
import com.autonavi.yunda.yunji.core.vo.response.InterfaceConfigDetailVO;
import com.autonavi.yunda.yunji.core.vo.response.InterfaceUriGroupVO;
import com.autonavi.yunda.yunji.service.BucUserService;
import com.autonavi.yunda.yunji.service.OperationRecordService;
import com.autonavi.yunda.yunji.service.ProjectAuthService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.List;

/**
 * @author cizhong.wcs
 * @date 2022/3/7 7:33 下午
 */
@Slf4j
@RestController
@RequestMapping("/interface/v3")
public class InterfaceController {

    @Resource
    private InterfaceConfigService interfaceConfigService;
    @Resource
    private FalconInterfaceService falconInterfaceService;
    @Resource
    private IIpService skylineIpServiceImpl;
    @Resource
    private ProjectAuthService projectAuthService;
    @Resource
    private BucUserService bucUserService;
    @Resource
    private OperationRecordService operationRecordService;
    @Resource
    private ProjectService projectService;
    @Resource
    private ApplicationEnvConfig applicationEnvConfig;

    @GetMapping("getDetailById")
    public InterfaceConfigDetailVO list(Long id) {
        InterfaceConfigDTO dto = interfaceConfigService.findByIdOrThrow(id);
        ProjectDTO projectDTO = projectService.findByProjectIdOrThrow(dto.getProjectId());
        return InterfaceConfigDetailVO.from(dto, projectDTO);

    }

    /**
     * 分页查询以uri分组的接口配置
     */
    @PostMapping("listUriGroup")
    public InterfaceUriGroupVO listUriGroup(@Validated @RequestBody InterfaceQueryCondition condition) {
        List<String> projectIds = projectAuthService.listAuthorizedProjectIds();
        condition.setProjectIds(projectIds);
        return interfaceConfigService.listInterfaceUriGroup(condition);
    }

    @DecodeExtraData
    @NeedOperationLog(operationName = "interface.add")
    @PostMapping("add")
    public Long add(@RequestBody @Validated InterfaceConfigRequest request) {
        projectAuthService.checkProjectPermission(request.getProjectId());
        String empId = bucUserService.getCurEmployeeIdOrNull();
        Long id = interfaceConfigService.add(request.toAddDTO(empId));
        operationRecordService.add(OperationRecordType.InterfaceSubType.CREATE, id.toString());
        return id;
    }

    /**
     * 新建版本
     */
    @NeedOperationLog(operationName = "interface.upgrade")
    @GetMapping("upgrade")
    public Long upgrade(Long id) {
        projectAuthService.checkInterfaceProjectPermission(id);
        String empId = bucUserService.getCurEmployeeIdOrNull();
        Long newId = interfaceConfigService.upgrade(id, empId);
        operationRecordService.add(OperationRecordType.InterfaceSubType.UPGRADE, newId.toString());
        return newId;
    }

    @DecodeExtraData
    @NeedOperationLog(operationName = "interface.update")
    @PostMapping("update")
    public void update(@RequestBody @Validated InterfaceConfigUpdateRequest request) {
        projectAuthService.checkInterfaceProjectPermission(request.getId());
        InterfaceConfigDTO dto = interfaceConfigService.findByIdOrThrow(request.getId());
        if (applicationEnvConfig.isPublish() && dto.getStatus().publishing()) {
            throw new AmapException(AmapExceptionCode.COMMON_SERVER_WARN, "线上环境 已发布或灰度中的接口不能进行更新,请先下线接口或升级接口版本.");
        }
        interfaceConfigService.update(request.fetchUpdateWrapper(dto, bucUserService.getCurEmployeeIdOrNull()));
        operationRecordService.add(OperationRecordType.InterfaceSubType.UPDATE, request.getId().toString());
    }
    /**
     * 灰度发布
     */
    @NeedOperationLog(operationName = "interface.grayPublish")
    @PostMapping("grayPublish")
    public void grayPublish(@RequestBody @Validated GrayPublishRequest request) {
        projectAuthService.checkInterfaceProjectPermission(request.id);
        interfaceConfigService.grayPublish(request.id, request.ips);
        interfaceConfigService.notifyEngine(request.id);
        operationRecordService.add(OperationRecordType.InterfaceSubType.GRAY_PUBLISH, request.id.toString());
    }

    /**
     * 取消灰度
     */
    @NeedOperationLog(operationName = "interface.cancelGrayPublish")
    @GetMapping("cancelGrayPublish")
    public void cancelGrayPublish(@RequestParam Long id) {
        projectAuthService.checkInterfaceProjectPermission(id);
        interfaceConfigService.cancelGrayPublish(id);
        interfaceConfigService.notifyEngine(id);
        operationRecordService.add(OperationRecordType.InterfaceSubType.CANCEL_GRAY_PUBLISH, id.toString());
    }

    /**
     * 进入待验证(预发,生产使用)
     */
    @DecodeExtraData
    @NeedOperationLog(operationName = "interface.enterValidating")
    @PostMapping("enterValidating")
    public void enterValidating(@RequestBody @Validated InterfaceConfigRequest request) {
        // 验证项目是否存在（如果不存在，就抛出异常）
        projectAuthService.checkProjectPermission(request.getProjectId());
        String empId = bucUserService.getCurEmployeeIdOrNull();
        Long id = interfaceConfigService.enterValidating(request.toValidatingDTO(empId));
        operationRecordService.add(OperationRecordType.InterfaceSubType.ENTER_VALIDATING, id.toString());
    }

    /**
     * 全量发布
     */
    @NeedOperationLog(operationName = "interface.publish")
    @GetMapping("publish")
    public void publish(@RequestParam Long id) {
        projectAuthService.checkInterfaceProjectPermission(id);
        String employeeId = bucUserService.getCurEmployeeId();
        try {
            falconInterfaceService.syncFalcon(id, employeeId);
        } catch (Exception e) {
            log.error("接口同步falcon失败,id = {}", id, e);
        }
        interfaceConfigService.publish(id);
        interfaceConfigService.notifyEngine(id);
        operationRecordService.add(OperationRecordType.InterfaceSubType.PUBLISH, id.toString());
    }

    /**
     * 下线
     */
    @NeedOperationLog(operationName = "interface.offline")
    @GetMapping("offline")
    public void offline(@RequestParam Long id) {
        projectAuthService.checkInterfaceProjectPermission(id);
        interfaceConfigService.offline(id);
        interfaceConfigService.notifyEngine(id);
        operationRecordService.add(OperationRecordType.InterfaceSubType.OFFLINE, id.toString());
    }

    /**
     * 强制调试成功
     */
    @NeedOperationLog(operationName = "interface.forceTestSuccess")
    @GetMapping("/forceTestSuccess")
    public void forceTestSuccess(@RequestParam Long id) {
        projectAuthService.checkInterfaceProjectPermission(id);
        interfaceConfigService.forceTestSuccess(id);
        operationRecordService.add(OperationRecordType.InterfaceSubType.FORCE_TEST_SUCCESS, id.toString());
    }

    @NeedOperationLog(operationName = "interface.syncFalcon")
    @GetMapping("syncFalcon")
    public void syncFalcon(@RequestParam Long id) {
        projectAuthService.checkInterfaceProjectPermission(id);
        falconInterfaceService.syncFalcon(id, bucUserService.getCurEmployeeId());
    }

    @NeedOperationLog(operationName = "interface.convertToComponent")
    @GetMapping("convertToComponent")
    public void convertToComponent(@RequestParam Long id) {
        projectAuthService.checkInterfaceProjectPermission(id);
        interfaceConfigService.convertToComponent(id, bucUserService.getCurEmployeeIdOrNull());
        operationRecordService.add(OperationRecordType.InterfaceSubType.CONVERT_TO_COMPONENT, id.toString());
    }

    @GetMapping("fetchIpList")
    public List<String> fetchIpList() {
        return skylineIpServiceImpl.fetchEngineIpList();
    }

    @NeedOperationLog(operationName = "interface.delete")
    @GetMapping("delete")
    public void delete(@RequestParam Long id) {
        projectAuthService.checkInterfaceProjectPermission(id);
        operationRecordService.add(OperationRecordType.InterfaceSubType.DELETE, id.toString());
        interfaceConfigService.delete(id);
    }

    @NeedOperationLog(operationName = "interface.updateExposedRestapi")
    @GetMapping("updateExposedRestapi")
    public void updateExposedRestapi(@RequestParam Long id, @RequestParam Boolean isExpose) {
        projectAuthService.checkSuperAdminPermission();
        interfaceConfigService.updateExposedRestapi(id, isExpose, bucUserService.getCurEmployeeIdOrNull());
        if (isExpose) {
            operationRecordService.add(OperationRecordType.InterfaceSubType.EXPOSED_RESTAPI, id.toString());
        } else {
            operationRecordService.add(OperationRecordType.InterfaceSubType.REVOKE_EXPOSED_RESTAPI, id.toString());
        }
    }
}
